home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 14 / Example 14.1 / heightMap.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-06-30  |  5.6 KB  |  230 lines

  1. #include "heightMap.h"
  2. #include "debug.h"
  3.  
  4. DWORD FtoDword(float f){return *((DWORD*)&f);}
  5.  
  6. float Noise(int x)
  7. {
  8.     x = (x<<13) ^ x;
  9.     return (1.0 - ((x * (x*x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);    
  10. }
  11.  
  12. float CosInterpolate(float v1, float v2, float a)
  13. {
  14.     float angle = a * D3DX_PI;
  15.     float prc = (1.0f - cos(angle)) * 0.5f;
  16.     return  v1*(1.0f - prc) + v2*prc;
  17. }
  18.  
  19. HEIGHTMAP::HEIGHTMAP(INTPOINT _size, float _maxHeight)
  20. {
  21.     try
  22.     {
  23.         m_size = _size;
  24.         m_maxHeight = _maxHeight;
  25.  
  26.         m_pHeightMap = new float[m_size.x * m_size.y];
  27.         memset(m_pHeightMap, 0, sizeof(float)*m_size.x*m_size.y);
  28.     }
  29.     catch(...)
  30.     {
  31.         debug.Print("Error in HEIGHTMAP::HEIGHTMAP()");
  32.     }
  33. }
  34.  
  35. HEIGHTMAP::~HEIGHTMAP()
  36. {
  37.     Release();
  38. }
  39.  
  40. void HEIGHTMAP::operator*=(const HEIGHTMAP &rhs)
  41. {
  42.     for(int y=0;y<m_size.y;y++)
  43.         for(int x=0;x<m_size.x;x++)
  44.         {
  45.             float a = m_pHeightMap[x + y * m_size.x] / m_maxHeight;
  46.             float b = 1.0f;
  47.             if(x <= rhs.m_size.x && y <= rhs.m_size.y)
  48.                 b = rhs.m_pHeightMap[x + y * m_size.x] / rhs.m_maxHeight;
  49.  
  50.             m_pHeightMap[x + y * m_size.x] = a * b * m_maxHeight;
  51.         }
  52. }
  53.  
  54. void HEIGHTMAP::Release()
  55. {
  56.     if(m_pHeightMap != NULL)delete [] m_pHeightMap;
  57.     m_pHeightMap = NULL;
  58. }
  59.  
  60. HRESULT HEIGHTMAP::LoadFromFile(IDirect3DDevice9* Device, char fileName[])
  61. {
  62.     try
  63.     {
  64.         //Reset the heightMap to 0.0f
  65.         memset(m_pHeightMap, 0, sizeof(float) * m_size.x * m_size.y);
  66.  
  67.         //Initiate the texture variables
  68.         IDirect3DTexture9 *heightMapTexture = NULL;
  69.         D3DXIMAGE_INFO info;
  70.  
  71.         //Load the texture (and scale it to our heightMap m_size)
  72.         if(FAILED(D3DXCreateTextureFromFileEx(Device, fileName, m_size.x, m_size.y, 1, D3DUSAGE_DYNAMIC, 
  73.                                             D3DFMT_L8, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 
  74.                                             NULL, &info, NULL, &heightMapTexture)))return E_FAIL;
  75.  
  76.         //Lock the texture
  77.         D3DLOCKED_RECT sRect;
  78.         heightMapTexture->LockRect(0, &sRect, NULL, NULL);
  79.         BYTE *bytes = (BYTE*)sRect.pBits;
  80.  
  81.         //Extract height values from the texture
  82.         for(int y=0;y<m_size.y;y++)
  83.             for(int x=0;x<m_size.x;x++)
  84.                 {
  85.                     BYTE *b = bytes + y * sRect.Pitch + x;
  86.                     m_pHeightMap[x + y * m_size.x] = (*b / 255.0f) * m_maxHeight;
  87.                 }
  88.                         
  89.         //Unlock the texture
  90.         heightMapTexture->UnlockRect(0);
  91.  
  92.         //Release texture
  93.         heightMapTexture->Release();
  94.     }
  95.     catch(...)
  96.     {
  97.         debug.Print("Error in HEIGHTMAP::LoadFromFile()");
  98.     }
  99.  
  100.     return S_OK;
  101. }
  102.  
  103. HRESULT HEIGHTMAP::CreateRandomHeightMap(int seed, float noiseSize, float persistence, int octaves)
  104. {
  105.     //For each map node
  106.     for(int y=0;y<m_size.y;y++)
  107.         for(int x=0;x<m_size.x;x++)
  108.         {
  109.             //Scale x & y to the range of 0.0 - m_size
  110.             float xf = ((float)x / (float)m_size.x) * noiseSize;
  111.             float yf = ((float)y / (float)m_size.y) * noiseSize;
  112.  
  113.             float total = 0;            
  114.  
  115.             // For each octave
  116.             for(int i=0;i<octaves;i++)
  117.             {
  118.                 //Calculate frequency and amplitude (different for each octave)
  119.                 float freq = pow(2, i);
  120.                 float amp = pow(persistence, i);
  121.  
  122.                 //Calculate the x,y noise coordinates
  123.                 float tx = xf * freq;
  124.                 float ty = yf * freq;
  125.                 int tx_int = tx;
  126.                 int ty_int = ty;
  127.  
  128.                 //Calculate the fractions of x & y
  129.                 float fracX = tx - tx_int;
  130.                 float fracY = ty - ty_int;
  131.  
  132.                 //Get the noise of this octave for each of these 4 points
  133.                 float v1 = Noise(tx_int + ty_int * 57 + seed);
  134.                 float v2 = Noise(tx_int+ 1 + ty_int * 57 + seed);
  135.                 float v3 = Noise(tx_int + (ty_int+1) * 57 + seed);
  136.                 float v4 = Noise(tx_int + 1 + (ty_int+1) * 57 + seed);
  137.  
  138.                 //Smooth in the X-axis
  139.                 float i1 = CosInterpolate(v1 , v2 , fracX);
  140.                 float i2 = CosInterpolate(v3 , v4 , fracX);
  141.  
  142.                 //Smooth in the Y-axis
  143.                 total += CosInterpolate(i1 , i2 , fracY) * amp;
  144.             }
  145.  
  146.             int b = 128 + total * 128.0f;
  147.             if(b < 0)b = 0;
  148.             if(b > 255)b = 255;
  149.  
  150.             //Save to heightMap
  151.             m_pHeightMap[x + y * m_size.x] = (b / 255.0f) * m_maxHeight;
  152.         }
  153.  
  154.     return S_OK;
  155. }
  156.  
  157. void HEIGHTMAP::RaiseTerrain(RECT r, float f)
  158. {
  159.     for(int y=r.top;y<=r.bottom;y++)
  160.         for(int x=r.left;x<=r.right;x++)
  161.         {
  162.             m_pHeightMap[x + y * m_size.x] += f;
  163.             if(m_pHeightMap[x + y * m_size.x] < -m_maxHeight)m_pHeightMap[x + y * m_size.x] = -m_maxHeight;
  164.             if(m_pHeightMap[x + y * m_size.x] > m_maxHeight)m_pHeightMap[x + y * m_size.x] = m_maxHeight;
  165.         }
  166. }
  167.  
  168. void HEIGHTMAP::SmoothTerrain()
  169. {
  170.     //Create temporary heightmap
  171.     float *hm = new float[m_size.x * m_size.y];
  172.     memset(hm, 0, sizeof(float) * m_size.x * m_size.y);
  173.  
  174.     for(int y=0;y<m_size.y;y++)
  175.         for(int x=0;x<m_size.x;x++)
  176.         {
  177.             float totalHeight = 0.0f;
  178.             int noNodes = 0;
  179.  
  180.             for(int y1=y-1;y1<=y+1;y1++)
  181.                 for(int x1=x-1;x1<=x+1;x1++)
  182.                     if(x1 >= 0 && x1 < m_size.x && y1 >= 0 && y1 < m_size.y)
  183.                     {
  184.                         totalHeight += m_pHeightMap[x1 + y1 * m_size.x];
  185.                         noNodes++;
  186.                     }
  187.  
  188.             hm[x + y * m_size.x] = totalHeight / (float)noNodes;
  189.         }
  190.  
  191.     //Replace old heightmap with smoothed heightmap
  192.     delete [] m_pHeightMap;
  193.     m_pHeightMap = hm;
  194. }
  195.  
  196. void HEIGHTMAP::Cap(float capHeight)
  197. {
  198.     m_maxHeight = 0.0f;
  199.  
  200.     for(int y=0;y<m_size.y;y++)
  201.         for(int x=0;x<m_size.x;x++)
  202.         {
  203.             m_pHeightMap[x + y * m_size.x] -= capHeight;
  204.             if(m_pHeightMap[x + y * m_size.x] < 0.0f)
  205.                 m_pHeightMap[x + y * m_size.x] = 0.0f;
  206.  
  207.             if(m_pHeightMap[x + y * m_size.x] > m_maxHeight)
  208.                 m_maxHeight = m_pHeightMap[x + y * m_size.x];
  209.         }
  210. }
  211.  
  212. float HEIGHTMAP::GetHeight(int x, int y)
  213. {
  214.     if(x < 0 || x > m_size.x || y < 0 || y > m_size.y)
  215.         return 0.0f;
  216.  
  217.     try
  218.     {
  219.         return m_pHeightMap[x + y * m_size.x];
  220.     }
  221.     catch(...)
  222.     {
  223.         return 0.0f;
  224.     }
  225. }
  226.  
  227. float HEIGHTMAP::GetHeight(INTPOINT p)
  228. {
  229.     return GetHeight(p.x, p.y);
  230. }